package com.xpec.c4.service.module.schedule;


import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.RunnableScheduledFuture;
import java.util.concurrent.TimeUnit;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.xpec.c4.game.time.JobSchedule;
import com.xpec.c4.game.utility.GameUtility;
import com.xpec.c4.service.module.task.TaskTimer;


/**
 * 
 * @author yangbingyan
 *
 */
public class ModuleSchedule {
	
	private static final Log log = LogFactory.getLog(ModuleSchedule.class);


	/**
	 * 本区更新线程
	 */
	protected JobSchedule timer = new JobSchedule(1);

	/**
	 * 
	 */
	private Map<TaskTimer, JobObject> taskTable = new HashMap<TaskTimer, JobObject>();
	
	/**
	 * 
	 */
	public ModuleSchedule(){
	}

	/**
	 * 
	 * @param obj
	 */	
	public boolean add(TaskTimer obj){

		JobObject runObj = new JobObject(this);		
		runObj.setTaskTimer(obj);
		
		RunnableScheduledFuture<?> task = null;

		switch(obj.getTimerOption()){
		
		case TaskTimer.ONCE:			
			//System.err.println("11 QueueSize:" + timer.getQueue().size() + " TaskCount:" + timer.getTaskCount()  + " CompletedTaskCount:" + timer.getCompletedTaskCount() + " ActiveCount:" + timer.getActiveCount());
			task = (RunnableScheduledFuture<?>) timer.schedule(runObj, obj.getInitialDelay(), TimeUnit.MILLISECONDS);
			// TODO temp log
			//log.info("add one time task! timer:" + timer + " TaskTimer:" + obj + " JobObject:" + runObj + " task:"+task);
			//System.err.println("12 QueueSize:" + timer.getQueue().size() + " TaskCount:" + timer.getTaskCount()  + " CompletedTaskCount:" + timer.getCompletedTaskCount() + " ActiveCount:" + timer.getActiveCount());
			break;
		
			/**
			 * scheduleAtFixedRate 本身只要在execute中產生任何exception，則後續任務皆為放棄 ，次功能的workqueue為無界佇列，既使設定了maximumPoolSize也沒用
			 */
		case TaskTimer.LOOP:
			//System.err.println("21 QueueSize:" + timer.getQueue().size() + " TaskCount:" + timer.getTaskCount() + " ActiveCount:" + timer.getActiveCount());
			task = (RunnableScheduledFuture<?>) timer.scheduleAtFixedRate(runObj, obj.getInitialDelay(), obj.getPeriod(), TimeUnit.MILLISECONDS);
			//System.err.println("22 QueueSize:" + timer.getQueue().size() + " TaskCount:" + timer.getTaskCount() + " ActiveCount:" + timer.getActiveCount());
			break;
		}
		
		runObj.setTask(task);
		taskTable.put(obj, runObj);
		return (task != null);
	}
	
	/**
	 * 
	 * @param obj
	 */
	public boolean remove(TaskTimer obj){
		
		JobObject jo = taskTable.get(obj);

		// TODO temp log
		//log.info("remove task! src:" + obj + " dest:" + jo);
		
		if(jo != null && jo.getTask() != null){
			
			//log.info("remove task:"+ jo.getTask());
			//System.err.println("31 QueueSize:" + timer.getQueue().size() + " TaskCount:" + timer.getTaskCount() + " CompletedTaskCount:" + timer.getCompletedTaskCount() + " ActiveCount:" + timer.getActiveCount());
			timer.remove(jo.getTask());
			//System.err.println("32 QueueSize:" + timer.getQueue().size() + " TaskCount:" + timer.getTaskCount() + " CompletedTaskCount:" + timer.getCompletedTaskCount() + " ActiveCount:" + timer.getActiveCount());
			
			if(jo.getTask().cancel(true)){
				//log.info("task cancel success! task:" + jo.getTask());
				taskTable.remove(obj);
				return true;
			}
			else{
				log.info("task cancel fail! task:" + jo.getTask());
			}
			
			if(jo.getTask().isCancelled()){
				//log.info("task is cancelled! task:" + jo.getTask());
				taskTable.remove(obj);
				return true;				
			}
		}
		return false;
	}
	
	public void shutdown(){
		timer.shutdown();
//		JobExecutor.shutdown();
	}
	
}


/**
 * 
 * @author yangbingyan
 *
 */
class JobObject implements Runnable
{
	/**
	 * Log管理器
	 */
	private static final Log log = LogFactory.getLog(JobObject.class);
	
	/**
	 * 
	 */
	private TaskTimer taskTimer;
	
	/**
	 * 
	 */
	private RunnableScheduledFuture<?> task = null;

	/**
	 * 
	 */
	private ModuleSchedule moduleSchedule;
	
	public JobObject(ModuleSchedule o){
		moduleSchedule = o;
	}
	
	@Override
	public void run() 
	{
		try
		{
				// 時間到, 把命令放到module的TaskQueue內
				taskTimer.addToExecuteQueue();
				
				// 不需loop就移除
				if(moduleSchedule != null && taskTimer.getTimerOption() != TaskTimer.LOOP){
					moduleSchedule.remove(taskTimer);
				}
		}
		catch(Exception e)
		{
			if(log.isErrorEnabled())
			{
				log.error("<<JobObject>> Throw Exception !!");
				log.error(GameUtility.getCurMethodName(), e);
			}
		}
	}


	public void setTaskTimer(TaskTimer taskTimer) {
		this.taskTimer = taskTimer;
	}

	public TaskTimer getTaskTimer() {
		return taskTimer;
	}

	public void setTask(RunnableScheduledFuture<?> task) {
		this.task = task;
	}

	public RunnableScheduledFuture<?> getTask() {
		return task;
	}

}
